#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#include <fstream>
#include <iostream>
#include <errno.h>
#include <sys/timeb.h>
#include <signal.h> 
#include <unistd.h>

// http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html#AEN144

#define GETLN_DELAY_US 1000

#ifdef __WIN32__
  #include "COMPORT.HPP"
#else
  #include <termios.h>
#endif

#define MIN(a,b) (a>b?b:a)
#define DIGIT(a) (a<='9' ? a & 0x0f : (a & 0x0f) + 9)

#define WF_OK 1
#define WF_NOTOK 0
#define WF_TIO -1

int linepos;

#define MAX_LINELEN 1000

FILE* fd_xmit;
int fd; // serial port
struct sigaction act;
struct sigaction oldact;

int set_interface_attribs (int fd, int speed, int parity)
{
        struct termios tty;
        memset (&tty, 0, sizeof tty);
        if (tcgetattr (fd, &tty) != 0)
        {
                printf ("error %d from tcgetattr", errno);
                return -1;
        }

        cfsetospeed (&tty, speed);
        cfsetispeed (&tty, speed);

        tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
        // disable IGNBRK for mismatched speed tests; otherwise receive break
        // as \000 chars
        tty.c_iflag &= ~IGNBRK;         // ignore break signal
        tty.c_lflag = 0;                // no signaling chars, no echo,
                                        // no canonical processing
        tty.c_oflag = 0;                // no remapping, no delays
        tty.c_cc[VMIN]  = 0;            // read doesn't block
        tty.c_cc[VTIME] = 1;            // 0.5 seconds read timeout

        tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl

        tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
                                        // enable reading
        tty.c_cflag &= ~(PARENB | PARODD);      // shut off parity
        tty.c_cflag |= parity;
        tty.c_cflag &= ~CSTOPB;
        tty.c_cflag &= ~CRTSCTS;

        if (tcsetattr (fd, TCSANOW, &tty) != 0)
        {
                printf ("error %d from tcsetattr", errno);
                return -1;
        }
        return 0;
}

void
set_blocking (int fd, int should_block)
{
        struct termios tty;
        memset (&tty, 0, sizeof tty);
        if (tcgetattr (fd, &tty) != 0)
        {
                printf ("error %d from tggetattr", errno);
                return;
        }

        tty.c_cc[VMIN]  = should_block ? 1 : 0;
        tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

        if (tcsetattr (fd, TCSANOW, &tty) != 0)
                printf ("error %d setting term attributes", errno);
}


void myLogOpen(int* fd, char* devname) {
#ifdef __WIN32__
  mycomptr = new COMPort(devname);
  mycomptr->setBitRate(115200);
#else
  *fd = open(devname, O_NOCTTY | O_RDWR | O_NDELAY | O_NONBLOCK ); // | O_SYNC
  if (*fd < 0) printf("Fehler open file: %s\n" , devname);
     fcntl(fd, F_SETFL, FASYNC);

//  set_interface_attribs (*fd, B115200, ~PARENB);
  struct termios sio_tio;
  cfmakeraw(&sio_tio);
  cfsetispeed(&sio_tio,B115200);
  cfsetospeed(&sio_tio,B115200);
  	sio_tio.c_cflag &= ~PARENB;	// keine Parit?tbits
	sio_tio.c_cflag &= ~CSTOPB;	// nur ein Stop-bit
	// options.c_cflag |=  CSTOPB;	// 2 Stopbits
	sio_tio.c_cflag &= ~CSIZE;
	// l?sche Datenbitseinstellung, damit n?chster Befehl g?ltig ist
	sio_tio.c_cflag |= CS8;	// select 8 Databits
//	options.c_cflag &= ~CRTSCTS;	// disable Hardwareflow control
	sio_tio.c_lflag &= ~(ICANON |  ECHO| ISIG);	// raw data
//	cfmakeraw (&options);		// real raw!
	tcsetattr (*fd, TCSANOW, &sio_tio);
//devReader node(devname, nodefd, O_RDONLY | O_NDELA
  
  

#endif
  linepos = 0;
} // Konstruktor

char myGetc(int fd) {
static int nread;
static char c;
#ifdef __WIN32__
return mycomptr->read();
#else
nread = read(fd, &c , 1);
/*
while (nread <= 0) {
    usleep(20000);
    nread = read(nodefd, &c , 1);
    }
*/
if (nread>0) return c;
  else return -1;
#endif
}

int myGetLine(char *buf, int fd, int nmax) {
char c;
int anz;
for(;;) {
  c = myGetc(fd); //if (c>0) putchar(c);
  if (c<0) return -1;
  if (c>=32) {
    if (linepos<MAX_LINELEN-1) buf[linepos++] = c;
    } // if 
  else {
    if (linepos) {
        anz = linepos;
	buf[linepos] = 0;
	linepos = 0;
//	fprintf(logfd, "%s\n", buf);
//	printf("%s\n", buf);
	return anz;
	}
    } // else
  } //for

};

void stamp(char *s) {
static timeb currtime;
static long long currsec, currms;
static int currh, currm, currs;
  ftime(&currtime);
  currsec = currtime.time+7200 % (60*60*24); // CORR gmt
  currsec %= (60*60*24);
  currs = currsec;
  currh = currs / (60 * 60);
  currm = (currs / 60 ) % 60;
  currs = currs % 60;
  currms = currtime.millitm;
  sprintf(s,"%02d:%02d:%02d-%03lld" , currh, currm, currs, currms);
}


int waitfor(int fd, int tio, char *s, const char *c, int until = 0) {
int x = (tio * 1000) / GETLN_DELAY_US;
for(;;) { 
  if (myGetLine(s,fd,MAX_LINELEN)>0) {
    printf("waitline: %s %d\n", s, until);
    if (s[0] != '#') {
    	if (strcmp(s, c) == 0) return WF_OK;
    	else if (!until) return WF_NOTOK;
    	} 
    }
    usleep(GETLN_DELAY_US);
    x--;
    if (x <= 0) {
      printf("waitline: TIO\n");
      return WF_TIO;
      }
    
  } // for
} // waitfor
int waituntil(int fd, int tio, char *s, const char *c) {
  return waitfor(fd, tio, s, c, 1);
}


int sendData(int fd, char* picbuf) {
char txbuf[1000];
char s[1000];
txbuf[0] = 'L';
txbuf[1] = 0xff;
txbuf[2+128] = 0x0d;
//for (int i = 0; i<128;i++) txbuf[2+i] = (i & 0x3f) +0x30;
for( int line = 0; line < 1280; line++) {
/*	   	write(fd, "L", 1);
		write(fd, "\377", 1);
		write(fd, &picbuf[line*128+0x82], 128);
		write(fd, "\n" , 1); */
		memcpy(&txbuf[2] ,  &picbuf[line*128+0x82], 128);
		write(fd, txbuf, 131);
//		if ((line % 16) == 15)
		  if (waitfor(fd, 1000, s , "OK") != WF_OK) {
			printf("Fehler bei LINE %d\n" , line);
			return -1;
			}
		} // for
return 0;
}


int myDump(int fd) {
char s[MAX_LINELEN];
int x = 0;
char picbuf[200000];
int infile = open("einstein.bmp", O_RDONLY);
int nread = read(infile, picbuf, 1280*1024/8+0x82);
close(infile);
if (nread != 1280*1024/8+0x82) {
  printf("Wrong file size \n");
  return (-1);
  }


//write(fd, "\n", 1);
//printf("written newline\n");
usleep(100000);
write(fd, "O\n" , 2);
printf("written O\n");
// erstes Busy abwarten
if(waituntil(fd, 3000, s , "BUSY") != WF_OK) {
  printf("No Busy received !\n"); return -1;
  }
// jetzt weitere BUSYS abwarten
int res = WF_TIO;
while( (res=waitfor(fd, 2000, s , "BUSY")) == WF_OK) ;
if (res == WF_TIO) {
  printf("no answer from Device !\n");
  return -1;
  }
if(strcmp(s , "TIO") == 0) { // timeout open
  printf("Timeout Open\n");
  return -1;
  }
if(strcmp(s , "OK") == 0) { // Open OK
      return sendData(fd, picbuf);
  }
} // Locreader::dump

void my_handler(int x)
{
printf("\nBreak Signal received - closing files\n");
time_t rawtime;
time ( &rawtime );
if (fd_xmit > 0) {
  fprintf(fd_xmit,"\n# %s# Break Signal received - closing files\n" , 
	  ctime(&rawtime));
  fclose(fd_xmit);
  }
close(fd);
exit(0);
};

int main(int argc, char** argv) {
  
act.sa_handler = &my_handler;
sigaction(SIGINT, &act, &oldact);

fd_xmit = fopen("chronlog.txt" , "a+");
time_t rawtime;
time ( &rawtime );
fprintf(fd_xmit , "\n# Reopened %s" , ctime (&rawtime));
  
char buf[MAX_LINELEN];


//myLogOpen(&fd, "/dev/cu.usbserial-FTGHVOAJ");  
myLogOpen(&fd, "/dev/ttyUSB0");  

// flush input
char c[1000];
while (waitfor(fd, 100, c, "*") != WF_TIO) ;
printf("Flushed input\n");


int err = myDump(fd);
if (err!=0) printf("Err %d\n", err);

while (waitfor(fd, 100, c, "*") != WF_TIO) ;
printf("Flushed input\n");
close(fd);
}
